package com.ziytek.web.citizen.service;

import cn.idev.excel.util.StringUtils;
import com.ziytek.web.citizen.config.caffeine.CaffeineUtil;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import com.ziytek.web.citizen.constant.SettingConstant;
import com.ziytek.web.citizen.enums.ErrorTypeEnum;
import com.ziytek.web.citizen.enums.ResponseEnum;
import com.ziytek.web.citizen.mapper.BasicCabinetIpMapper;
import com.ziytek.web.citizen.model.bean.BrattyRealData;
import com.ziytek.web.citizen.model.req.StatusQueryReq;
import com.ziytek.web.citizen.model.rsp.StatusQueryRsp;
import com.ziytek.web.citizen.model.vo.StatusVo;
import com.ziytek.web.citizen.pojo.basic.BasicCabinetIp;
import com.ziytek.web.citizen.util.HexUtil;
import com.ziytek.web.citizen.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 机柜状态查询
 *
 * @author fenghx
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class StatusQueryService {
    private final RealtimeDataService realtimeDataService;
    private final BasicCabinetIpMapper basicCabinetIpMapper;

    public StatusQueryRsp statusQuery(StatusQueryReq req) {
        var rsp = new StatusQueryRsp();
        rsp.setRetErrorData("查询无数据");

        var cabinetNo = req.getCabinetNo();

        List<Integer> cabList = CaffeineUtil.get("cabList_key");
        if (CollectionUtils.isEmpty(cabList) && StringUtil.isNotEmpty(cabinetNo)) {
            cabList = new ArrayList<>();
            cabList.add(Integer.parseInt(cabinetNo));
            CaffeineUtil.set("cabList_key", cabList, 300);
        }
        if (CollectionUtils.isEmpty(cabList) && StringUtil.isEmpty(cabinetNo)) {
            cabList = new ArrayList<>();
            List<BasicCabinetIp> ips = basicCabinetIpMapper.queryAllByAvailable(SettingConstant.IS_AVAILABLE);
            if (!CollectionUtils.isEmpty(ips)) {
                for (var ip : ips) {
                    cabList.add(Integer.parseInt(ip.getCabinetNo()));
                }

                CaffeineUtil.set("cabList_key", cabList, 300);
            }
        }

        if (null == cabList || cabList.isEmpty()) {
            return rsp;
        }

        cabList.sort((Integer::compareTo));
        Set<Integer> set= cabList.stream().filter(Objects::nonNull).collect(Collectors.toSet());
        for (var cab : set) {
            rsp.setStatusVo(getStatusVoByCab(String.valueOf(cab)));
        }

        if (!CollectionUtils.isEmpty(rsp.getData())) {
            rsp.getData().sort(Comparator.comparingInt(o -> Integer.parseInt(o.getCabinetNo())));
        }
        rsp.setRetCode(ServerConstant.SUCCESS);
        rsp.setRetMsg(ResponseEnum.SUCCESS.getDesc());
        return rsp;
    }

    private StatusVo getStatusVoByCab(String cab) {
        if (StringUtil.isEmpty(cab)) {
            return getEmptyVo(cab);
        }

        var key = "statusVo_key_" + Integer.parseInt(cab);
        var result = realtimeDataService.getRealtimeDataQuery(cab);
        StatusVo vo = null == result ? CaffeineUtil.get(key) : null;
        vo = null == vo ? null != result && !CollectionUtils.isEmpty(result.getData())
                ? getStatusVo(result.getData(), cab) : getEmptyVo(cab) : vo;

//        if (null != vo && ServerConstant.STATUS_ONLINE.equalsIgnoreCase(vo.getStatus())) {
//            log.info("getStatusVoByCab 在线:{}", key);
//        }
        return vo;
    }

    private StatusVo getStatusVo(List<BrattyRealData> list, String cab) {
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }

        var vo = new StatusVo();
        vo.setCabinetNo(cab);
        int runsCount = NumConstant.INT_ZERO;
        int waitCount = NumConstant.INT_ZERO;
        int spacesCount = NumConstant.INT_ZERO;
        int faultsCount = NumConstant.INT_ZERO;
        int finishCount = NumConstant.INT_ZERO;
        for (var bd : list) {
            for (var bdData : bd.getDoorData()) {
                for (var one : bdData.getBatteriesList()) {
                    int exceptionType = one.getExceptionType();
                    if (ErrorTypeEnum.EXECUTION_COMPLETED.getCode() == exceptionType) {
                        finishCount += NumConstant.INT_ONE;
                    } else if (ErrorTypeEnum.EXECUTING.getCode() == exceptionType || ErrorTypeEnum.STOP.getCode() == exceptionType) {
                        runsCount += NumConstant.INT_ONE;
                    } else if (ErrorTypeEnum.WAITING.getCode() == exceptionType) {
                        waitCount += NumConstant.INT_ONE;
                    } else if (ErrorTypeEnum.REVERSE_BATTERY.getCode() == exceptionType
                            || ErrorTypeEnum.BATTERY_LIMIT.getCode() == exceptionType
                            || ErrorTypeEnum.PWM_ERROR.getCode() == exceptionType
                            || ErrorTypeEnum.CHECK_ERROR.getCode() == exceptionType) {
                        faultsCount += NumConstant.INT_ONE;
                    } else {
                        spacesCount += NumConstant.INT_ONE;
                    }
                }
            }
        }

        vo.setRunsCount(runsCount);
        vo.setWaitCount(waitCount);
        vo.setFinishCount(finishCount);
        vo.setFaultsCount(faultsCount);
        vo.setSpacesCount(spacesCount);
        // 查询设备在线离线状态if
        vo.setStatus("offline");
        var ips = basicCabinetIpMapper.queryByCabinetNo(HexUtil.fillZero(cab, NumConstant.INT_TWO), SettingConstant.IS_AVAILABLE);
        if (null != ips && StringUtils.isNotBlank(ips.getIp())) {
            //var off = CaffeineUtil.get(CaffeineUtil.CACHE_KEY_OFFLINE + ips.getIp());
            var online = CaffeineUtil.get(CaffeineUtil.CACHE_KEY_ONLINE + ips.getIp());
            vo.setStatus(null == online ? ServerConstant.STATUS_OFFLINE : ServerConstant.STATUS_ONLINE);
        }
        var key = "statusVo_key_" + Integer.parseInt(cab);
        long expire = ServerConstant.STATUS_ONLINE.equals(vo.getStatus()) ? 20 * 60 : 24 * 60 * 60;

        boolean hasData = vo.getFinishCount() > NumConstant.INT_ZERO || vo.getFaultsCount() > NumConstant.INT_ZERO
                || vo.getRunsCount() > NumConstant.INT_ZERO || vo.getWaitCount() > NumConstant.INT_ZERO;
        if (!hasData && ServerConstant.STATUS_OFFLINE.equalsIgnoreCase(vo.getStatus())) {
            vo.setRunsCount(NumConstant.INT_ZERO);
            vo.setWaitCount(NumConstant.INT_ZERO);
            vo.setSpacesCount(NumConstant.INT_ZERO);
            vo.setFaultsCount(NumConstant.INT_ZERO);
            vo.setFinishCount(NumConstant.INT_ZERO);
        }
        CaffeineUtil.set(key, vo, expire);
        return vo;
    }

    private StatusVo getEmptyVo(String cab) {
        var vo = new StatusVo();
        vo.setCabinetNo(cab);
        int runsCount = NumConstant.INT_ZERO;
        int waitCount = NumConstant.INT_ZERO;
        int spacesCount = NumConstant.INT_ZERO;
        int faultsCount = NumConstant.INT_ZERO;
        int finishCount = NumConstant.INT_ZERO;
        vo.setRunsCount(runsCount);
        vo.setWaitCount(waitCount);
        vo.setFinishCount(finishCount);
        vo.setFaultsCount(faultsCount);
        vo.setSpacesCount(spacesCount);
        vo.setStatus("offline");
        var key = "statusVo_key_" + Integer.parseInt(cab);
        CaffeineUtil.set(key, vo, 24 * 60 * 60);
        return vo;
    }
}
